#include "rtc.h"


Byte bcd2dec(Byte i)
{
	return (i & 0x0F) + 10 * ((i >> 4) & 0x0F);
}


Byte dec2bcd(Byte i)
{
	return (i % 10) + (((i / 10) % 10) << 4);
}


void rtc_int_enable()
{
	write_rtc(RTC_STAT_B, read_rtc(RTC_STAT_B) | RTC_PIE | RTC_AIE | RTC_UIE);
	//read_rtc(RTC_STAT_C);
	unmask_pic(RTC_IRQ);
}


void rtc_int_enable_periodic()
{
	//programar RTC para gerar periodic ints a um rate de 1024KHz
	write_rtc(RTC_STAT_A, (read_rtc(RTC_STAT_A) & 0xF0) | 0x06);
	
	//activar RTC periodic ints
	write_rtc(RTC_STAT_B, (read_rtc(RTC_STAT_B) & 0x8F) | RTC_PIE);
	read_rtc(RTC_STAT_C);
}


void rtc_int_disable()
{
	mask_pic(RTC_IRQ);
	write_rtc(RTC_STAT_B, read_rtc(RTC_STAT_B) & ~(RTC_PIE | RTC_AIE | RTC_UIE));
}


void rtc_valid()
{
	int old_pic1 = get_pic1(), old_pic2 = get_pic2();
	set_pic_var(0xFF, 0xFF);

	outportb(RTC_ADDR_REG, RTC_STAT_A); // read STAT_A
	
	// wait if Update In Progress (UIP)
	while (inportb(RTC_DATA_REG) & RTC_UIP)
	; // data is invalid
	
	set_pic_var(old_pic1, old_pic2);
}


Byte read_rtc(Byte add)
{
	int old_pic1 = get_pic1(), old_pic2 = get_pic2();
	set_pic_var(0xFF, 0xFF);

	outportb(RTC_ADDR_REG, add);
	Byte val = inportb(RTC_DATA_REG);

	set_pic_var(old_pic1, old_pic2);
	return val;
}


Byte read_rtcv(Byte add)
{
	rtc_valid();
	return read_rtc(add);
}


void write_rtc(Byte add, Byte value)
{
	int old_pic1 = get_pic1(), old_pic2 = get_pic2();
	set_pic_var(0xFF, 0xFF);

	outportb(RTC_ADDR_REG, add);
	outportb(RTC_DATA_REG, value);

	set_pic_var(old_pic1, old_pic2);
}


void write_rtcv(Byte add, Byte value)
{
	rtc_valid();
	write_rtc(add, value);
}


void rtc_read_time(RTC_TIME* rt)
{
	rt->hour = bcd2dec(read_rtcv(HOUR));
	rt->min = bcd2dec(read_rtcv(MIN));
	rt->sec = bcd2dec(read_rtcv(SEC));
}


void rtc_read_date(RTC_DATE* rd)
{
	rd->year = bcd2dec(read_rtcv(YEAR));
	rd->month = bcd2dec(read_rtcv(MONTH));
	rd->day = bcd2dec(read_rtcv(MONTH_DAY));
}


void rtc_read_alarm(RTC_TIME* rt)
{
	rt->hour = bcd2dec(read_rtcv(HOUR_ALARM));
	rt->min = bcd2dec(read_rtcv(MIN_ALARM));
	rt->sec = bcd2dec(read_rtcv(SEC_ALARM));
}


void rtc_write_alarm(RTC_TIME* rt)
{
	write_rtcv(HOUR_ALARM, dec2bcd(rt->hour));
	write_rtcv(MIN_ALARM, dec2bcd(rt->min));
	write_rtcv(SEC_ALARM, dec2bcd(rt->sec));
}
